library(tidyverse)
# this file generated by scripts/pca_workup_data_prep.R
load('../data/EiaD_pca_analysis_2023.Rdata')
emeta <- data.table::fread('../data/eyeIntegration22_meta_2023_03_03.csv.gz')
# from the Snakefile 2023
run_meta <- read_csv('../salmon_counts/run_meta.csv.gz')
Rows: 2517 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): log, date, version
dbl (3): align_perc, processed, mapped
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# from script/auto_label_tissue.R
predictions <- read_tsv('../data/2023_05_18_ML_tissue_predictions.tsv.gz')
Rows: 1132 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (5): study_accession, sample_id, sample_label, predict, predict_stringent
dbl (1): min_score
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pred_values <- read_tsv('../data/2023_05_18_ML_tissue_values.tsv.gz')
Rows: 1132 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): study_accession
dbl (6): Conjunctiva, Cornea, Lens, Retina, RPE, Trabecular Meshwork
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Run PCA
On count data which I have setup from (sc)EiaD
resources in scripts/pca_workup_data_prep.R
##################################################
# PCA time
library(matrixStats)
library(Matrix)
do_pca <- function(gene_by_sample, meta, ntop = 1000){
# count values for gene_by_sample
# metadata rows must match columns of gene_by_sample
# quick checker for data mismatch
if (!(colnames(gene_by_sample) == meta$sample_accession) %>% sum() == ncol(gene_by_sample)){
stop("Check metadata and matrix samples name matching")
}
gene_by_sample <- scale(((gene_by_sample)))
gene_by_sample <- log1p(gene_by_sample)
# remove RPL/RPS/MT genes from consideration
keep_genes <- grep('^RPS|^RPL|^MT-|^MPRS|^MPRL',row.names(gene_by_sample),value = TRUE, invert = TRUE)
gene_by_sample <- gene_by_sample[keep_genes,]
Pvars <- rowVars(gene_by_sample)
select <- order(Pvars, decreasing = TRUE)[seq_len(min(ntop,
length(Pvars)))]
PCA <- prcomp(t((gene_by_sample[select, ])), scale = FALSE)
percentVar <- round(100*PCA$sdev^2/sum(PCA$sdev^2),1)
dataGG = cbind(PCA$x, meta)
gene_names = PCA$rotation %>% rownames()
out <- list(PCA, dataGG, percentVar, select, gene_names)
out
}
# , study_accession != 'SRP273695'
mat_all_eye <- mat_all[,meta_mat_all %>% filter(Cohort == "Eye") %>% pull(sample_accession)]
mat_all_eye_meta <- meta_mat_all %>% filter(Cohort == 'Eye')
# hand run chunks below
# eye only
eye_out <- do_pca(mat_all_eye,
mat_all_eye_meta)
# PCA <- out[[1]]
# dataGG <- out[[2]]
# percentVar <- out[[3]]
# select <- out[[4]]
# all (including scRNA data scEiaD/plae)
#all_out <- do_pca(mat_all,meta_mat_all)
# PCA <- out[[1]]
# dataGG <- out[[2]]
# percentVar <- out[[3]]
# select <- out[[4]]
# all minus scRNA
# all
#bulk_out <- do_pca(mat_all[,(meta_mat_all %>% filter(Source != 'scRNA') %>% #pull(sample_accession))], meta_mat_all %>% filter(Source != 'scRNA') )
# all minus swaroop AMD
noAMD_out <- do_pca(mat_all[,(meta_mat_all %>% filter(!grepl("AMD", Perturbation)) %>% pull(sample_accession))], meta_mat_all %>% filter(!grepl("AMD", Perturbation)) )
Top level look
PC1 and PC2
PCA <- noAMD_out[[1]]
dataGG <- noAMD_out[[2]]
percentVar <- noAMD_out[[3]]
select <- noAMD_out[[4]]
pcFirst <- 'PC1'
pcSecond <- 'PC2'
rotations <- c(pcFirst, pcSecond)
top_rotations <-
c(PCA$rotation[,str_extract(pcFirst, '\\d+') %>% as.integer()] %>% sort() %>% head(3) %>% names(),
PCA$rotation[,str_extract(pcFirst, '\\d+') %>% as.integer()] %>% sort() %>% tail(3) %>% names(),
PCA$rotation[,str_extract(pcSecond, '\\d+') %>% as.integer()] %>% sort() %>% head(3) %>% names(),
PCA$rotation[,str_extract(pcSecond, '\\d+') %>% as.integer()] %>% sort() %>% tail(3) %>% names()) %>%
unique()
rotation_multipler_first <- dataGG[pcFirst] %>% pull(1) %>% abs() %>% max() / PCA$rotation[,str_extract(pcFirst, '\\d+') %>% as.integer()] %>% abs() %>% max()
rotation_multipler_second <- dataGG[pcSecond] %>% pull(1) %>% abs() %>% max() / PCA$rotation[,str_extract(pcSecond, '\\d+') %>% as.integer()] %>% abs() %>% max()
dataGG %>%
#filter(Source != 'scRNA') %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]])) +
geom_point(size=3, aes(color=Tissue, shape = Source)) +
geom_segment(data = PCA$rotation[top_rotations,rotations] %>% data.frame(), aes(x=0,y=0, xend = .data[[pcFirst]]*rotation_multipler_first, yend = .data[[pcSecond]]*rotation_multipler_second)) +
ggrepel::geom_label_repel(data = PCA$rotation[top_rotations,rotations] %>%
as_tibble(rownames = 'Gene') %>%
mutate(Gene = gsub(' \\(.*','',Gene)),
aes(x=.data[[pcFirst]]*rotation_multipler_first, y = .data[[pcSecond]] * rotation_multipler_second, label = Gene)) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>% as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>% as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_color_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_fill_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_shape_manual(values = 0:10)

dataGG %>%
#filter(Source != 'scRNA') %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]])) +
geom_point(size=3, aes(color=Tissue, shape = Source)) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>% as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>% as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_color_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_fill_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_shape_manual(values = 0:10) +
facet_wrap(~Tissue)

Split by Tissue and Color by Min Score
Where lower values are more confident in the eigenProjectR tissue
score
dataGG %>%
filter(Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")) %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
left_join(predictions, by = c('sample_accession' = 'sample_id')) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]])) +
geom_point(size=3, aes(color=min_score, shape = Source)) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>% as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>% as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_color_viridis_c() +
scale_shape_manual(values = 0:10) + facet_wrap(~Tissue)

Split by Tissue and Color by Mislabel(?)
Where lower values are more confident in the eigenProjectR tissue
score
for (i in c(1,3,5,7,9)){
pcFirst <- paste0('PC', i)
pcSecond <- paste0('PC', i+1)
sus <- predictions %>% filter(sample_label != predict)
print(dataGG %>%
filter(Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")) %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
mutate(Suspicious = case_when(sample_accession %in% sus$sample_id ~ 'Yes')) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]])) +
geom_point(size=3, aes(color=Suspicious, shape = Source)) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>%
as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>%
as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_shape_manual(values = 0:10) + facet_wrap(~Tissue)
)}





UMAP
Add meta info for whether the eigenProjectR tissue labelling suspects
and issue (“Sus”)
custom.settings = umap::umap.defaults
custom.settings$n_neighbors = 30
custom.settings$metric <- 'euclidean'
custom.settings$min_dist <- 0.5
library(plotly)
umap <- umap::umap(PCA$x[,1:100], config = custom.settings)
p <- umap$layout %>% as_tibble(rownames = 'sample_accession') %>%
left_join(dataGG, by = 'sample_accession') %>%
left_join(predictions, by = c("sample_accession" = "sample_id")) %>%
mutate(lab = paste0(predict, ' (', min_score, ')\n', sample_accession, '\n', Age)) %>%
# mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
# Cohort == 'Body' ~ 'Body',
# TRUE ~ Tissue)) %>%
ggplot(aes(x=V1,y=V2, label = lab)) +
geom_point(size=3, aes(color=Tissue, shape = Source)) +
cowplot::theme_cowplot() +
scale_color_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_fill_manual(values = c(pals::glasbey(), pals::alphabet2(), pals::alphabet2()) %>% unname()) +
scale_shape_manual(values = 0:10)
Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.
ggplotly(p)
Plot PCA and color by total reads
Was suspicious that PC2 was being driven by total counts … nope! Not
the case
run_meta <- read_csv('../salmon_counts/run_meta.csv.gz')
Rows: 2517 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): log, date, version
dbl (3): align_perc, processed, mapped
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pcFirst <- 'PC1'
pcSecond <- 'PC2'
dataGG %>%
#filter(Source != 'scRNA') %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
left_join(
run_meta %>% mutate(sample_accession = gsub('salmon_quant\\/|\\/aux_info\\/meta_info.json','',log))) %>%
mutate(Sus = case_when(sample_accession %in% sus$sample_id ~ 'Yes') ,
Age = case_when(is.na(Age) ~ 'None', TRUE ~ Age),
processed = log1p(processed) %>% round(., digits = 0)) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]])) +
geom_point(size=1, aes(color=log1p(processed))) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>% as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>% as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_color_viridis_c() + facet_wrap(~processed)
Joining with `by = join_by(sample_accession)`

Heatmap of eigenProjectR scoring
library(ComplexHeatmap)
hm_df <- cbind(predictions, pred_values)
row.names(hm_df) <- hm_df$sample_id
ha_side = rowAnnotation(df = data.frame(ScientistLabel =
hm_df$sample_label %>% factor(levels = unique(hm_df$sample_label)),
eigenLabel =
hm_df$predict %>% factor(levels = unique(hm_df$sample_label))),
col = list(ScientistLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname()),
eigenLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname())))
Heatmap(hm_df[,8:13],
right_annotation = ha_side,
cluster_rows = FALSE)
Warning: The input is a data frame-like object, convert it to a matrix.

Just the “mislabelled” ones
hm_df <- cbind(predictions, pred_values %>% select(-study_accession)) %>% filter(sample_label != predict)
row.names(hm_df) <- hm_df$sample_id
ha_side = rowAnnotation(df = data.frame(ScientistLabel =
hm_df$sample_label %>% factor(levels = unique(hm_df$sample_label)),
eigenLabel =
hm_df$predict %>% factor(levels = unique(hm_df$sample_label))),
col = list(ScientistLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname()),
eigenLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname())))
Heatmap(hm_df[,7:12],
right_annotation = ha_side, cluster_rows = FALSE)
Warning: The input is a data frame-like object, convert it to a matrix.

One plot per study with any mislabels
studies_with_sus <- emeta %>% filter(sample_accession %in% sus$sample_id) %>% pull(study_accession) %>% unique()
full_df <- cbind(predictions, pred_values %>% select(-study_accession))
for (i in studies_with_sus){
hm_df <- cbind(predictions, pred_values %>% select(-study_accession)) %>% filter(study_accession %in% i)
row.names(hm_df) <- hm_df$sample_id
ha_side = rowAnnotation(df = data.frame(ScientistLabel =
hm_df$sample_label %>% factor(levels = unique(full_df$sample_label)),
eigenLabel =
hm_df$predict %>% factor(levels = unique(full_df$sample_label))),
col = list(ScientistLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname()),
eigenLabel = c("Conjunctiva" = pals::alphabet2(20)[2] %>% unname(),
"Cornea" = pals::alphabet2(20)[3] %>% unname(),
"Lens" = pals::alphabet2(20)[6] %>% unname(),
"Retina" = pals::alphabet2(20)[10] %>% unname(),
"RPE" = pals::alphabet2(20)[13] %>% unname(),
"Trabecular Meshwork" = pals::alphabet2(20)[16] %>% unname())))
print(Heatmap(as.matrix(hm_df[,7:12]),
right_annotation = ha_side, cluster_rows = FALSE, column_title = i))
pcFirst <- "PC1"
pcSecond <- 'PC2'
print(dataGG %>%
filter(study_accession == i,
Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")) %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
mutate(Suspicious = case_when(sample_accession %in% sus$sample_id ~ 'Yes')) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]], label = sample_accession)) +
geom_point(data = dataGG %>%
filter(study_accession != i) %>%
filter(Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")), size=2, aes(x =.data[[pcFirst]], y= .data[[pcSecond]]), color = 'grey' ) +
geom_point(size=3, aes(color=Suspicious, shape = Source)) +
ggrepel::geom_label_repel( size = 2.5, max.overlaps = Inf) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>%
as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>%
as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_shape_manual(values = 0:10) + facet_wrap(~Tissue, ncol = 2)
)
pcFirst <- "PC3"
pcSecond <- 'PC4'
print(dataGG %>%
filter(study_accession == i,
Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")) %>%
as_tibble() %>%
mutate(Tissue = case_when(Tissue == 'Brain' ~ Tissue,
Cohort == 'Body' ~ 'Body',
TRUE ~ Tissue)) %>%
mutate(Suspicious = case_when(sample_accession %in% sus$sample_id ~ 'Yes')) %>%
ggplot(., aes(.data[[pcFirst]], .data[[pcSecond]], label = sample_accession)) +
geom_point(data = dataGG %>%
filter(study_accession != i) %>%
filter(Tissue %in% c("Conjunctiva", "Cornea", "Lens", "Retina","RPE","Trabecular Meshwork")),
size=2,
aes(x =.data[[pcFirst]], y= .data[[pcSecond]]), color = 'grey' ) +
geom_point(size=3, aes(color=Suspicious, shape = Source)) +
ggrepel::geom_label_repel(size = 2.5, max.overlaps = Inf) +
xlab(paste0(pcFirst, ": ",percentVar[str_extract(pcFirst, '\\d+') %>%
as.integer()],"% variance")) +
ylab(paste0(pcSecond, ": ",percentVar[str_extract(pcSecond, '\\d+') %>%
as.integer()],"% variance")) +
cowplot::theme_cowplot() +
scale_shape_manual(values = 0:10) + facet_wrap(~Tissue, ncol = 2)
)
}































































LS0tCnRpdGxlOiAiUENBIGFuZCBlaWdlblByb2plY3RSIExhYmVsIEFuYWx5c2lzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBhdXRob3I6ICJEYXZpZCBNY0dhdWdoZXkiCiAgICBkYXRlOiAiMjAyMS0wNS0xNCIKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKIyB0aGlzIGZpbGUgZ2VuZXJhdGVkIGJ5IHNjcmlwdHMvcGNhX3dvcmt1cF9kYXRhX3ByZXAuUgpsb2FkKCcuLi9kYXRhL0VpYURfcGNhX2FuYWx5c2lzXzIwMjMuUmRhdGEnKQoKZW1ldGEgPC0gZGF0YS50YWJsZTo6ZnJlYWQoJy4uL2RhdGEvZXllSW50ZWdyYXRpb24yMl9tZXRhXzIwMjNfMDNfMDMuY3N2Lmd6JykKCiMgZnJvbSB0aGUgU25ha2VmaWxlIDIwMjMgCnJ1bl9tZXRhIDwtIHJlYWRfY3N2KCcuLi9zYWxtb25fY291bnRzL3J1bl9tZXRhLmNzdi5neicpCgojIGZyb20gc2NyaXB0L2F1dG9fbGFiZWxfdGlzc3VlLlIKcHJlZGljdGlvbnMgPC0gcmVhZF90c3YoJy4uL2RhdGEvMjAyM18wNV8xOF9NTF90aXNzdWVfcHJlZGljdGlvbnMudHN2Lmd6JykKcHJlZF92YWx1ZXMgPC0gcmVhZF90c3YoJy4uL2RhdGEvMjAyM18wNV8xOF9NTF90aXNzdWVfdmFsdWVzLnRzdi5neicpCmBgYAoKIyBSdW4gUENBIAoKT24gKipjb3VudCoqIGRhdGEgd2hpY2ggSSBoYXZlIHNldHVwIGZyb20gKHNjKUVpYUQgcmVzb3VyY2VzIGluIHNjcmlwdHMvcGNhX3dvcmt1cF9kYXRhX3ByZXAuUiAKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBDQSB0aW1lCgpsaWJyYXJ5KG1hdHJpeFN0YXRzKQpsaWJyYXJ5KE1hdHJpeCkKCmRvX3BjYSA8LSBmdW5jdGlvbihnZW5lX2J5X3NhbXBsZSwgbWV0YSwgbnRvcCA9IDEwMDApewogICMgY291bnQgdmFsdWVzIGZvciBnZW5lX2J5X3NhbXBsZQogICMgbWV0YWRhdGEgcm93cyBtdXN0IG1hdGNoIGNvbHVtbnMgb2YgZ2VuZV9ieV9zYW1wbGUKICAjIHF1aWNrIGNoZWNrZXIgZm9yIGRhdGEgbWlzbWF0Y2gKICBpZiAoIShjb2xuYW1lcyhnZW5lX2J5X3NhbXBsZSkgPT0gbWV0YSRzYW1wbGVfYWNjZXNzaW9uKSAlPiUgc3VtKCkgPT0gbmNvbChnZW5lX2J5X3NhbXBsZSkpewogICAgc3RvcCgiQ2hlY2sgbWV0YWRhdGEgYW5kIG1hdHJpeCBzYW1wbGVzIG5hbWUgbWF0Y2hpbmciKQogIH0KICBnZW5lX2J5X3NhbXBsZSA8LSBzY2FsZSgoKGdlbmVfYnlfc2FtcGxlKSkpCiAgZ2VuZV9ieV9zYW1wbGUgPC0gbG9nMXAoZ2VuZV9ieV9zYW1wbGUpCiAgIyByZW1vdmUgUlBML1JQUy9NVCBnZW5lcyBmcm9tIGNvbnNpZGVyYXRpb24gCiAga2VlcF9nZW5lcyA8LSBncmVwKCdeUlBTfF5SUEx8Xk1ULXxeTVBSU3xeTVBSTCcscm93Lm5hbWVzKGdlbmVfYnlfc2FtcGxlKSx2YWx1ZSA9IFRSVUUsIGludmVydCA9IFRSVUUpCiAgZ2VuZV9ieV9zYW1wbGUgPC0gZ2VuZV9ieV9zYW1wbGVba2VlcF9nZW5lcyxdCiAgUHZhcnMgPC0gcm93VmFycyhnZW5lX2J5X3NhbXBsZSkKICBzZWxlY3QgPC0gb3JkZXIoUHZhcnMsIGRlY3JlYXNpbmcgPSBUUlVFKVtzZXFfbGVuKG1pbihudG9wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgoUHZhcnMpKSldCiAgUENBIDwtIHByY29tcCh0KChnZW5lX2J5X3NhbXBsZVtzZWxlY3QsIF0pKSwgc2NhbGUgPSBGQUxTRSkKICBwZXJjZW50VmFyIDwtIHJvdW5kKDEwMCpQQ0Ekc2Rldl4yL3N1bShQQ0Ekc2Rldl4yKSwxKQogIAogIGRhdGFHRyA9IGNiaW5kKFBDQSR4LCBtZXRhKQogIGdlbmVfbmFtZXMgPSBQQ0Ekcm90YXRpb24gJT4lIHJvd25hbWVzKCkKICBvdXQgPC0gbGlzdChQQ0EsIGRhdGFHRywgcGVyY2VudFZhciwgc2VsZWN0LCBnZW5lX25hbWVzKQogIG91dAp9CgojICwgc3R1ZHlfYWNjZXNzaW9uICE9ICdTUlAyNzM2OTUnCm1hdF9hbGxfZXllIDwtIG1hdF9hbGxbLG1ldGFfbWF0X2FsbCAlPiUgZmlsdGVyKENvaG9ydCA9PSAiRXllIikgJT4lIHB1bGwoc2FtcGxlX2FjY2Vzc2lvbildCm1hdF9hbGxfZXllX21ldGEgPC0gbWV0YV9tYXRfYWxsICU+JSBmaWx0ZXIoQ29ob3J0ID09ICdFeWUnKQoKIyBoYW5kIHJ1biBjaHVua3MgYmVsb3cKIyBleWUgb25seQpleWVfb3V0IDwtIGRvX3BjYShtYXRfYWxsX2V5ZSwKICAgICAgICAgICAgICAgICAgbWF0X2FsbF9leWVfbWV0YSkKIyBQQ0EgPC0gb3V0W1sxXV0KIyBkYXRhR0cgPC0gb3V0W1syXV0KIyBwZXJjZW50VmFyIDwtIG91dFtbM11dCiMgc2VsZWN0IDwtIG91dFtbNF1dCgojIGFsbCAoaW5jbHVkaW5nIHNjUk5BIGRhdGEgc2NFaWFEL3BsYWUpCiNhbGxfb3V0IDwtIGRvX3BjYShtYXRfYWxsLG1ldGFfbWF0X2FsbCkKIyBQQ0EgPC0gb3V0W1sxXV0KIyBkYXRhR0cgPC0gb3V0W1syXV0KIyBwZXJjZW50VmFyIDwtIG91dFtbM11dCiMgc2VsZWN0IDwtIG91dFtbNF1dCgojIGFsbCBtaW51cyBzY1JOQQojIGFsbAojYnVsa19vdXQgPC0gZG9fcGNhKG1hdF9hbGxbLChtZXRhX21hdF9hbGwgJT4lIGZpbHRlcihTb3VyY2UgIT0gJ3NjUk5BJykgJT4lICNwdWxsKHNhbXBsZV9hY2Nlc3Npb24pKV0sIG1ldGFfbWF0X2FsbCAlPiUgZmlsdGVyKFNvdXJjZSAhPSAnc2NSTkEnKSApCgojIGFsbCBtaW51cyBzd2Fyb29wIEFNRApub0FNRF9vdXQgPC0gZG9fcGNhKG1hdF9hbGxbLChtZXRhX21hdF9hbGwgJT4lIGZpbHRlcighZ3JlcGwoIkFNRCIsIFBlcnR1cmJhdGlvbikpICU+JSBwdWxsKHNhbXBsZV9hY2Nlc3Npb24pKV0sIG1ldGFfbWF0X2FsbCAlPiUgZmlsdGVyKCFncmVwbCgiQU1EIiwgUGVydHVyYmF0aW9uKSkgKQpgYGAKCiMgVG9wIGxldmVsIGxvb2sKCiMjIFBDMSBhbmQgUEMyCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KUENBIDwtIG5vQU1EX291dFtbMV1dCmRhdGFHRyA8LSBub0FNRF9vdXRbWzJdXQpwZXJjZW50VmFyIDwtIG5vQU1EX291dFtbM11dCnNlbGVjdCA8LSBub0FNRF9vdXRbWzRdXQoKcGNGaXJzdCA8LSAnUEMxJwpwY1NlY29uZCA8LSAnUEMyJwpyb3RhdGlvbnMgPC0gYyhwY0ZpcnN0LCBwY1NlY29uZCkKCgp0b3Bfcm90YXRpb25zIDwtIAogIGMoUENBJHJvdGF0aW9uWyxzdHJfZXh0cmFjdChwY0ZpcnN0LCAnXFxkKycpICU+JSBhcy5pbnRlZ2VyKCldICU+JSBzb3J0KCkgJT4lIGhlYWQoMykgJT4lIG5hbWVzKCksCiAgICBQQ0Ekcm90YXRpb25bLHN0cl9leHRyYWN0KHBjRmlyc3QsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0gJT4lIHNvcnQoKSAlPiUgdGFpbCgzKSAlPiUgbmFtZXMoKSwKICAgIFBDQSRyb3RhdGlvblssc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0gJT4lIHNvcnQoKSAlPiUgaGVhZCgzKSAlPiUgbmFtZXMoKSwKICAgIFBDQSRyb3RhdGlvblssc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0gJT4lIHNvcnQoKSAlPiUgdGFpbCgzKSAlPiUgbmFtZXMoKSkgJT4lIAogIHVuaXF1ZSgpCgpyb3RhdGlvbl9tdWx0aXBsZXJfZmlyc3QgPC0gZGF0YUdHW3BjRmlyc3RdICU+JSBwdWxsKDEpICU+JSBhYnMoKSAlPiUgbWF4KCkgLyBQQ0Ekcm90YXRpb25bLHN0cl9leHRyYWN0KHBjRmlyc3QsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0gJT4lIGFicygpICU+JSBtYXgoKQpyb3RhdGlvbl9tdWx0aXBsZXJfc2Vjb25kIDwtIGRhdGFHR1twY1NlY29uZF0gJT4lIHB1bGwoMSkgJT4lIGFicygpICU+JSBtYXgoKSAvIFBDQSRyb3RhdGlvblssc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0gJT4lIGFicygpICU+JSBtYXgoKQoKZGF0YUdHICU+JQogICNmaWx0ZXIoU291cmNlICE9ICdzY1JOQScpICU+JSAKICBhc190aWJibGUoKSAlPiUgCiAgbXV0YXRlKFRpc3N1ZSA9IGNhc2Vfd2hlbihUaXNzdWUgPT0gJ0JyYWluJyB+IFRpc3N1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvaG9ydCA9PSAnQm9keScgfiAnQm9keScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gVGlzc3VlKSkgJT4lIAogIGdncGxvdCguLCBhZXMoLmRhdGFbW3BjRmlyc3RdXSwgLmRhdGFbW3BjU2Vjb25kXV0pKSArCiAgZ2VvbV9wb2ludChzaXplPTMsIGFlcyhjb2xvcj1UaXNzdWUsIHNoYXBlID0gU291cmNlKSkgKwogIGdlb21fc2VnbWVudChkYXRhID0gUENBJHJvdGF0aW9uW3RvcF9yb3RhdGlvbnMscm90YXRpb25zXSAlPiUgZGF0YS5mcmFtZSgpLCBhZXMoeD0wLHk9MCwgeGVuZCA9IC5kYXRhW1twY0ZpcnN0XV0qcm90YXRpb25fbXVsdGlwbGVyX2ZpcnN0LCB5ZW5kID0gLmRhdGFbW3BjU2Vjb25kXV0qcm90YXRpb25fbXVsdGlwbGVyX3NlY29uZCkpICsKICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPSBQQ0Ekcm90YXRpb25bdG9wX3JvdGF0aW9ucyxyb3RhdGlvbnNdICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKHJvd25hbWVzID0gJ0dlbmUnKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShHZW5lID0gZ3N1YignIFxcKC4qJywnJyxHZW5lKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9LmRhdGFbW3BjRmlyc3RdXSpyb3RhdGlvbl9tdWx0aXBsZXJfZmlyc3QsIHkgPSAuZGF0YVtbcGNTZWNvbmRdXSAqIHJvdGF0aW9uX211bHRpcGxlcl9zZWNvbmQsIGxhYmVsID0gR2VuZSkpICsKICB4bGFiKHBhc3RlMChwY0ZpcnN0LCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNGaXJzdCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAocGNTZWNvbmQsICI6ICIscGVyY2VudFZhcltzdHJfZXh0cmFjdChwY1NlY29uZCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMocGFsczo6Z2xhc2JleSgpLCBwYWxzOjphbHBoYWJldDIoKSwgcGFsczo6YWxwaGFiZXQyKCkpICU+JSB1bm5hbWUoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMocGFsczo6Z2xhc2JleSgpLCBwYWxzOjphbHBoYWJldDIoKSwgcGFsczo6YWxwaGFiZXQyKCkpICU+JSB1bm5hbWUoKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSAwOjEwKSAKCgpkYXRhR0cgJT4lCiAgI2ZpbHRlcihTb3VyY2UgIT0gJ3NjUk5BJykgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtdXRhdGUoVGlzc3VlID0gY2FzZV93aGVuKFRpc3N1ZSA9PSAnQnJhaW4nIH4gVGlzc3VlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29ob3J0ID09ICdCb2R5JyB+ICdCb2R5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBUaXNzdWUpKSAlPiUgCiAgZ2dwbG90KC4sIGFlcyguZGF0YVtbcGNGaXJzdF1dLCAuZGF0YVtbcGNTZWNvbmRdXSkpICsKICBnZW9tX3BvaW50KHNpemU9MywgYWVzKGNvbG9yPVRpc3N1ZSwgc2hhcGUgPSBTb3VyY2UpKSArCiAgeGxhYihwYXN0ZTAocGNGaXJzdCwgIjogIixwZXJjZW50VmFyW3N0cl9leHRyYWN0KHBjRmlyc3QsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0sIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKHBjU2Vjb25kLCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIGFzLmludGVnZXIoKV0sIiUgdmFyaWFuY2UiKSkgKyAKICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKHBhbHM6OmdsYXNiZXkoKSwgcGFsczo6YWxwaGFiZXQyKCksIHBhbHM6OmFscGhhYmV0MigpKSAlPiUgdW5uYW1lKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKHBhbHM6OmdsYXNiZXkoKSwgcGFsczo6YWxwaGFiZXQyKCksIHBhbHM6OmFscGhhYmV0MigpKSAlPiUgdW5uYW1lKCkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMDoxMCkgKwogIGZhY2V0X3dyYXAoflRpc3N1ZSkKCmBgYAoKIyBTcGxpdCBieSBUaXNzdWUgYW5kIENvbG9yIGJ5IE1pbiBTY29yZQpXaGVyZSBsb3dlciB2YWx1ZXMgYXJlIG1vcmUgY29uZmlkZW50IGluIHRoZSBlaWdlblByb2plY3RSIHRpc3N1ZSBzY29yZQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTh9CmRhdGFHRyAlPiUKICBmaWx0ZXIoVGlzc3VlICVpbiUgYygiQ29uanVuY3RpdmEiLCAiQ29ybmVhIiwgIkxlbnMiLCAiUmV0aW5hIiwiUlBFIiwiVHJhYmVjdWxhciBNZXNod29yayIpKSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIG11dGF0ZShUaXNzdWUgPSBjYXNlX3doZW4oVGlzc3VlID09ICdCcmFpbicgfiBUaXNzdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2hvcnQgPT0gJ0JvZHknIH4gJ0JvZHknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IFRpc3N1ZSkpICU+JSAKICBsZWZ0X2pvaW4ocHJlZGljdGlvbnMsIGJ5ID0gYygnc2FtcGxlX2FjY2Vzc2lvbicgPSAnc2FtcGxlX2lkJykpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKC5kYXRhW1twY0ZpcnN0XV0sIC5kYXRhW1twY1NlY29uZF1dKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0zLCBhZXMoY29sb3I9bWluX3Njb3JlLCBzaGFwZSA9IFNvdXJjZSkpICsKICB4bGFiKHBhc3RlMChwY0ZpcnN0LCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNGaXJzdCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAocGNTZWNvbmQsICI6ICIscGVyY2VudFZhcltzdHJfZXh0cmFjdChwY1NlY29uZCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSAwOjEwKSArIGZhY2V0X3dyYXAoflRpc3N1ZSkKYGBgCgojIFNwbGl0IGJ5IFRpc3N1ZSBhbmQgQ29sb3IgYnkgTWlzbGFiZWwoPykKV2hlcmUgbG93ZXIgdmFsdWVzIGFyZSBtb3JlIGNvbmZpZGVudCBpbiB0aGUgZWlnZW5Qcm9qZWN0UiB0aXNzdWUgc2NvcmUKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQoKZm9yIChpIGluIGMoMSwzLDUsNyw5KSl7CiAgcGNGaXJzdCA8LSBwYXN0ZTAoJ1BDJywgaSkKICBwY1NlY29uZCA8LSBwYXN0ZTAoJ1BDJywgaSsxKQogIHN1cyA8LSBwcmVkaWN0aW9ucyAlPiUgZmlsdGVyKHNhbXBsZV9sYWJlbCAhPSBwcmVkaWN0KQogIAogIHByaW50KGRhdGFHRyAlPiUKICAgICAgICAgIGZpbHRlcihUaXNzdWUgJWluJSBjKCJDb25qdW5jdGl2YSIsICJDb3JuZWEiLCAiTGVucyIsICJSZXRpbmEiLCJSUEUiLCJUcmFiZWN1bGFyIE1lc2h3b3JrIikpICU+JSAKICAgICAgICAgIGFzX3RpYmJsZSgpICU+JSAKICAgICAgICAgIG11dGF0ZShUaXNzdWUgPSBjYXNlX3doZW4oVGlzc3VlID09ICdCcmFpbicgfiBUaXNzdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvaG9ydCA9PSAnQm9keScgfiAnQm9keScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBUaXNzdWUpKSAlPiUgCiAgICAgICAgICBtdXRhdGUoU3VzcGljaW91cyA9IGNhc2Vfd2hlbihzYW1wbGVfYWNjZXNzaW9uICVpbiUgc3VzJHNhbXBsZV9pZCB+ICdZZXMnKSkgJT4lIAogICAgICAgICAgZ2dwbG90KC4sIGFlcyguZGF0YVtbcGNGaXJzdF1dLCAuZGF0YVtbcGNTZWNvbmRdXSkpICsKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBhZXMoY29sb3I9U3VzcGljaW91cywgc2hhcGUgPSBTb3VyY2UpKSArCiAgICAgICAgICB4bGFiKHBhc3RlMChwY0ZpcnN0LCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNGaXJzdCwgJ1xcZCsnKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5pbnRlZ2VyKCldLCIlIHZhcmlhbmNlIikpICsKICAgICAgICAgIHlsYWIocGFzdGUwKHBjU2Vjb25kLCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmludGVnZXIoKV0sIiUgdmFyaWFuY2UiKSkgKyAKICAgICAgICAgIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArCiAgICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMDoxMCkgKyBmYWNldF93cmFwKH5UaXNzdWUpCiAgKX0KCmBgYAoKIyBVTUFQCkFkZCBtZXRhIGluZm8gZm9yIHdoZXRoZXIgdGhlIGVpZ2VuUHJvamVjdFIgdGlzc3VlIGxhYmVsbGluZyBzdXNwZWN0cyBhbmQgaXNzdWUgKCJTdXMiKQoKYGBge3J9CmN1c3RvbS5zZXR0aW5ncyA9IHVtYXA6OnVtYXAuZGVmYXVsdHMKY3VzdG9tLnNldHRpbmdzJG5fbmVpZ2hib3JzID0gMzAKY3VzdG9tLnNldHRpbmdzJG1ldHJpYyA8LSAnZXVjbGlkZWFuJwpjdXN0b20uc2V0dGluZ3MkbWluX2Rpc3QgPC0gMC41CmxpYnJhcnkocGxvdGx5KQp1bWFwIDwtIHVtYXA6OnVtYXAoUENBJHhbLDE6MTAwXSwgY29uZmlnID0gY3VzdG9tLnNldHRpbmdzKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9MTV9CnAgPC0gdW1hcCRsYXlvdXQgJT4lIGFzX3RpYmJsZShyb3duYW1lcyA9ICdzYW1wbGVfYWNjZXNzaW9uJykgJT4lIAogIAogIGxlZnRfam9pbihkYXRhR0csIGJ5ID0gJ3NhbXBsZV9hY2Nlc3Npb24nKSAlPiUgCiAgbGVmdF9qb2luKHByZWRpY3Rpb25zLCBieSA9IGMoInNhbXBsZV9hY2Nlc3Npb24iID0gInNhbXBsZV9pZCIpKSAlPiUgCiAgbXV0YXRlKGxhYiA9ICBwYXN0ZTAocHJlZGljdCwgJyAoJywgbWluX3Njb3JlLCAnKVxuJywgc2FtcGxlX2FjY2Vzc2lvbiwgJ1xuJywgQWdlKSkgJT4lIAogICMgbXV0YXRlKFRpc3N1ZSA9IGNhc2Vfd2hlbihUaXNzdWUgPT0gJ0JyYWluJyB+IFRpc3N1ZSwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICBDb2hvcnQgPT0gJ0JvZHknIH4gJ0JvZHknLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBUaXNzdWUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PVYxLHk9VjIsIGxhYmVsID0gbGFiKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MywgYWVzKGNvbG9yPVRpc3N1ZSwgc2hhcGUgPSBTb3VyY2UpKSArCiAgY293cGxvdDo6dGhlbWVfY293cGxvdCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhwYWxzOjpnbGFzYmV5KCksIHBhbHM6OmFscGhhYmV0MigpLCBwYWxzOjphbHBoYWJldDIoKSkgJT4lIHVubmFtZSgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhwYWxzOjpnbGFzYmV5KCksIHBhbHM6OmFscGhhYmV0MigpLCBwYWxzOjphbHBoYWJldDIoKSkgJT4lIHVubmFtZSgpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDA6MTApCmdncGxvdGx5KHApCmBgYAoKCiMjIFBsb3QgUENBIGFuZCBjb2xvciBieSB0b3RhbCByZWFkcwpXYXMgc3VzcGljaW91cyB0aGF0IFBDMiB3YXMgYmVpbmcgZHJpdmVuIGJ5IHRvdGFsIGNvdW50cyAuLi4gbm9wZSEgTm90IHRoZSBjYXNlCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KcnVuX21ldGEgPC0gcmVhZF9jc3YoJy4uL3NhbG1vbl9jb3VudHMvcnVuX21ldGEuY3N2Lmd6JykKcGNGaXJzdCA8LSAnUEMxJwpwY1NlY29uZCA8LSAnUEMyJwpkYXRhR0cgJT4lCiAgI2ZpbHRlcihTb3VyY2UgIT0gJ3NjUk5BJykgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtdXRhdGUoVGlzc3VlID0gY2FzZV93aGVuKFRpc3N1ZSA9PSAnQnJhaW4nIH4gVGlzc3VlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29ob3J0ID09ICdCb2R5JyB+ICdCb2R5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBUaXNzdWUpKSAlPiUgCiAgbGVmdF9qb2luKAogICAgcnVuX21ldGEgJT4lIG11dGF0ZShzYW1wbGVfYWNjZXNzaW9uID0gZ3N1Yignc2FsbW9uX3F1YW50XFwvfFxcL2F1eF9pbmZvXFwvbWV0YV9pbmZvLmpzb24nLCcnLGxvZykpKSAlPiUgCiAgbXV0YXRlKFN1cyA9IGNhc2Vfd2hlbihzYW1wbGVfYWNjZXNzaW9uICVpbiUgc3VzJHNhbXBsZV9pZCB+ICdZZXMnKSAsCiAgICAgICAgIEFnZSA9IGNhc2Vfd2hlbihpcy5uYShBZ2UpIH4gJ05vbmUnLCBUUlVFIH4gQWdlKSwKICAgICAgICAgcHJvY2Vzc2VkID0gbG9nMXAocHJvY2Vzc2VkKSAlPiUgcm91bmQoLiwgZGlnaXRzID0gMCkpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKC5kYXRhW1twY0ZpcnN0XV0sIC5kYXRhW1twY1NlY29uZF1dKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0xLCBhZXMoY29sb3I9bG9nMXAocHJvY2Vzc2VkKSkpICsKICB4bGFiKHBhc3RlMChwY0ZpcnN0LCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNGaXJzdCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAocGNTZWNvbmQsICI6ICIscGVyY2VudFZhcltzdHJfZXh0cmFjdChwY1NlY29uZCwgJ1xcZCsnKSAlPiUgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkgKyBmYWNldF93cmFwKH5wcm9jZXNzZWQpCmBgYAoKIyBIZWF0bWFwIG9mIGVpZ2VuUHJvamVjdFIgc2NvcmluZwpgYGB7ciwgZmlnLmhlaWdodD0xMjAsIGZpZy53aWR0aD0xMH0KbGlicmFyeShDb21wbGV4SGVhdG1hcCkKaG1fZGYgPC0gY2JpbmQocHJlZGljdGlvbnMsIHByZWRfdmFsdWVzKQpyb3cubmFtZXMoaG1fZGYpIDwtIGhtX2RmJHNhbXBsZV9pZAoKaGFfc2lkZSA9IHJvd0Fubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKFNjaWVudGlzdExhYmVsID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhtX2RmJHNhbXBsZV9sYWJlbCAlPiUgZmFjdG9yKGxldmVscyA9IHVuaXF1ZShobV9kZiRzYW1wbGVfbGFiZWwpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVpZ2VuTGFiZWwgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG1fZGYkcHJlZGljdCAlPiUgZmFjdG9yKGxldmVscyA9IHVuaXF1ZShobV9kZiRzYW1wbGVfbGFiZWwpKSksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoU2NpZW50aXN0TGFiZWwgPSBjKCJDb25qdW5jdGl2YSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzJdICU+JSB1bm5hbWUoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JuZWEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVszXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMZW5zIiA9IHBhbHM6OmFscGhhYmV0MigyMClbNl0gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmV0aW5hIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMTBdICU+JSB1bm5hbWUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJQRSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzEzXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUcmFiZWN1bGFyIE1lc2h3b3JrIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMTZdICU+JSB1bm5hbWUoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWlnZW5MYWJlbCA9IGMoIkNvbmp1bmN0aXZhIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMl0gJT4lIHVubmFtZSgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29ybmVhIiA9IHBhbHM6OmFscGhhYmV0MigyMClbM10gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMZW5zIiA9IHBhbHM6OmFscGhhYmV0MigyMClbNl0gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZXRpbmEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxMF0gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSUEUiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxM10gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUcmFiZWN1bGFyIE1lc2h3b3JrIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMTZdICU+JSB1bm5hbWUoKSkpKQoKCkhlYXRtYXAoaG1fZGZbLDg6MTNdLCAKICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gaGFfc2lkZSwKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSkKYGBgCiMgSnVzdCB0aGUgIm1pc2xhYmVsbGVkIiBvbmVzCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQoKaG1fZGYgPC0gY2JpbmQocHJlZGljdGlvbnMsIHByZWRfdmFsdWVzICU+JSBzZWxlY3QoLXN0dWR5X2FjY2Vzc2lvbikpICU+JSBmaWx0ZXIoc2FtcGxlX2xhYmVsICE9IHByZWRpY3QpCnJvdy5uYW1lcyhobV9kZikgPC0gaG1fZGYkc2FtcGxlX2lkCgpoYV9zaWRlID0gcm93QW5ub3RhdGlvbihkZiA9IGRhdGEuZnJhbWUoU2NpZW50aXN0TGFiZWwgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG1fZGYkc2FtcGxlX2xhYmVsICU+JSBmYWN0b3IobGV2ZWxzID0gdW5pcXVlKGhtX2RmJHNhbXBsZV9sYWJlbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWlnZW5MYWJlbCA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBobV9kZiRwcmVkaWN0ICU+JSBmYWN0b3IobGV2ZWxzID0gdW5pcXVlKGhtX2RmJHNhbXBsZV9sYWJlbCkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChTY2llbnRpc3RMYWJlbCA9IGMoIkNvbmp1bmN0aXZhIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMl0gJT4lIHVubmFtZSgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvcm5lYSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzNdICU+JSB1bm5hbWUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxlbnMiID0gcGFsczo6YWxwaGFiZXQyKDIwKVs2XSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZXRpbmEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxMF0gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUlBFIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMTNdICU+JSB1bm5hbWUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyYWJlY3VsYXIgTWVzaHdvcmsiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxNl0gJT4lIHVubmFtZSgpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlaWdlbkxhYmVsID0gYygiQ29uanVuY3RpdmEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsyXSAlPiUgdW5uYW1lKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JuZWEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVszXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxlbnMiID0gcGFsczo6YWxwaGFiZXQyKDIwKVs2XSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJldGluYSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzEwXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJQRSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzEzXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyYWJlY3VsYXIgTWVzaHdvcmsiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxNl0gJT4lIHVubmFtZSgpKSkpCgoKSGVhdG1hcChobV9kZlssNzoxMl0sIAogICAgICAgIHJpZ2h0X2Fubm90YXRpb24gPSBoYV9zaWRlLCBjbHVzdGVyX3Jvd3MgPSBGQUxTRSkKYGBgCgojIE9uZSBwbG90IHBlciBzdHVkeSB3aXRoIGFueSBtaXNsYWJlbHMKCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9CnN0dWRpZXNfd2l0aF9zdXMgPC0gZW1ldGEgJT4lIGZpbHRlcihzYW1wbGVfYWNjZXNzaW9uICVpbiUgc3VzJHNhbXBsZV9pZCkgJT4lIHB1bGwoc3R1ZHlfYWNjZXNzaW9uKSAlPiUgdW5pcXVlKCkKCmZ1bGxfZGYgPC0gY2JpbmQocHJlZGljdGlvbnMsIHByZWRfdmFsdWVzICU+JSBzZWxlY3QoLXN0dWR5X2FjY2Vzc2lvbikpIApmb3IgKGkgaW4gc3R1ZGllc193aXRoX3N1cyl7CiAgaG1fZGYgPC0gY2JpbmQocHJlZGljdGlvbnMsIHByZWRfdmFsdWVzICU+JSBzZWxlY3QoLXN0dWR5X2FjY2Vzc2lvbikpICU+JSBmaWx0ZXIoc3R1ZHlfYWNjZXNzaW9uICVpbiUgaSkKICByb3cubmFtZXMoaG1fZGYpIDwtIGhtX2RmJHNhbXBsZV9pZAogIAogIGhhX3NpZGUgPSByb3dBbm5vdGF0aW9uKGRmID0gZGF0YS5mcmFtZShTY2llbnRpc3RMYWJlbCA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhtX2RmJHNhbXBsZV9sYWJlbCAlPiUgZmFjdG9yKGxldmVscyA9IHVuaXF1ZShmdWxsX2RmJHNhbXBsZV9sYWJlbCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlaWdlbkxhYmVsID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG1fZGYkcHJlZGljdCAlPiUgZmFjdG9yKGxldmVscyA9IHVuaXF1ZShmdWxsX2RmJHNhbXBsZV9sYWJlbCkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KFNjaWVudGlzdExhYmVsID0gYygiQ29uanVuY3RpdmEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsyXSAlPiUgdW5uYW1lKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JuZWEiID0gcGFsczo6YWxwaGFiZXQyKDIwKVszXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxlbnMiID0gcGFsczo6YWxwaGFiZXQyKDIwKVs2XSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJldGluYSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzEwXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJQRSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzEzXSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyYWJlY3VsYXIgTWVzaHdvcmsiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxNl0gJT4lIHVubmFtZSgpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVpZ2VuTGFiZWwgPSBjKCJDb25qdW5jdGl2YSIgPSBwYWxzOjphbHBoYWJldDIoMjApWzJdICU+JSB1bm5hbWUoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29ybmVhIiA9IHBhbHM6OmFscGhhYmV0MigyMClbM10gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxlbnMiID0gcGFsczo6YWxwaGFiZXQyKDIwKVs2XSAlPiUgdW5uYW1lKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmV0aW5hIiA9IHBhbHM6OmFscGhhYmV0MigyMClbMTBdICU+JSB1bm5hbWUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSUEUiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxM10gJT4lIHVubmFtZSgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyYWJlY3VsYXIgTWVzaHdvcmsiID0gcGFsczo6YWxwaGFiZXQyKDIwKVsxNl0gJT4lIHVubmFtZSgpKSkpCiAgCiAgCiAgcHJpbnQoSGVhdG1hcChhcy5tYXRyaXgoaG1fZGZbLDc6MTJdKSwgCiAgICAgICAgICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gaGFfc2lkZSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIGNvbHVtbl90aXRsZSA9IGkpKQogIAogIHBjRmlyc3QgPC0gIlBDMSIKICBwY1NlY29uZCA8LSAnUEMyJwogIHByaW50KGRhdGFHRyAlPiUKICAgICAgICAgIGZpbHRlcihzdHVkeV9hY2Nlc3Npb24gPT0gaSwKICAgICAgICAgICAgICAgICBUaXNzdWUgJWluJSBjKCJDb25qdW5jdGl2YSIsICJDb3JuZWEiLCAiTGVucyIsICJSZXRpbmEiLCJSUEUiLCJUcmFiZWN1bGFyIE1lc2h3b3JrIikpICU+JSAKICAgICAgICAgIGFzX3RpYmJsZSgpICU+JSAKICAgICAgICAgIG11dGF0ZShUaXNzdWUgPSBjYXNlX3doZW4oVGlzc3VlID09ICdCcmFpbicgfiBUaXNzdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvaG9ydCA9PSAnQm9keScgfiAnQm9keScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBUaXNzdWUpKSAlPiUgCiAgICAgICAgICBtdXRhdGUoU3VzcGljaW91cyA9IGNhc2Vfd2hlbihzYW1wbGVfYWNjZXNzaW9uICVpbiUgc3VzJHNhbXBsZV9pZCB+ICdZZXMnKSkgJT4lIAogICAgICAgICAgZ2dwbG90KC4sIGFlcyguZGF0YVtbcGNGaXJzdF1dLCAuZGF0YVtbcGNTZWNvbmRdXSwgbGFiZWwgPSBzYW1wbGVfYWNjZXNzaW9uKSkgKwogICAgICAgICAgCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhR0cgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihzdHVkeV9hY2Nlc3Npb24gIT0gaSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihUaXNzdWUgJWluJSBjKCJDb25qdW5jdGl2YSIsICJDb3JuZWEiLCAiTGVucyIsICJSZXRpbmEiLCJSUEUiLCJUcmFiZWN1bGFyIE1lc2h3b3JrIikpLCBzaXplPTIsIGFlcyh4ID0uZGF0YVtbcGNGaXJzdF1dLCB5PSAuZGF0YVtbcGNTZWNvbmRdXSksIGNvbG9yID0gJ2dyZXknICkgKwogICAgICAgICAgZ2VvbV9wb2ludChzaXplPTMsIGFlcyhjb2xvcj1TdXNwaWNpb3VzLCBzaGFwZSA9IFNvdXJjZSkpICsKICAgICAgICAgIAogICAgICAgICAgZ2dyZXBlbDo6Z2VvbV9sYWJlbF9yZXBlbCggc2l6ZSA9IDIuNSwgbWF4Lm92ZXJsYXBzID0gSW5mKSArCiAgICAgICAgICB4bGFiKHBhc3RlMChwY0ZpcnN0LCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNGaXJzdCwgJ1xcZCsnKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5pbnRlZ2VyKCldLCIlIHZhcmlhbmNlIikpICsKICAgICAgICAgIHlsYWIocGFzdGUwKHBjU2Vjb25kLCAiOiAiLHBlcmNlbnRWYXJbc3RyX2V4dHJhY3QocGNTZWNvbmQsICdcXGQrJykgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmludGVnZXIoKV0sIiUgdmFyaWFuY2UiKSkgKyAKICAgICAgICAgIGNvd3Bsb3Q6OnRoZW1lX2Nvd3Bsb3QoKSArCiAgICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMDoxMCkgKyBmYWNldF93cmFwKH5UaXNzdWUsIG5jb2wgPSAyKQogICkKICAKICBwY0ZpcnN0IDwtICJQQzMiCiAgcGNTZWNvbmQgPC0gJ1BDNCcKICBwcmludChkYXRhR0cgJT4lCiAgICAgICAgICBmaWx0ZXIoc3R1ZHlfYWNjZXNzaW9uID09IGksCiAgICAgICAgICAgICAgICAgVGlzc3VlICVpbiUgYygiQ29uanVuY3RpdmEiLCAiQ29ybmVhIiwgIkxlbnMiLCAiUmV0aW5hIiwiUlBFIiwiVHJhYmVjdWxhciBNZXNod29yayIpKSAlPiUgCiAgICAgICAgICBhc190aWJibGUoKSAlPiUgCiAgICAgICAgICBtdXRhdGUoVGlzc3VlID0gY2FzZV93aGVuKFRpc3N1ZSA9PSAnQnJhaW4nIH4gVGlzc3VlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2hvcnQgPT0gJ0JvZHknIH4gJ0JvZHknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gVGlzc3VlKSkgJT4lIAogICAgICAgICAgbXV0YXRlKFN1c3BpY2lvdXMgPSBjYXNlX3doZW4oc2FtcGxlX2FjY2Vzc2lvbiAlaW4lIHN1cyRzYW1wbGVfaWQgfiAnWWVzJykpICU+JSAKICAgICAgICAgIGdncGxvdCguLCBhZXMoLmRhdGFbW3BjRmlyc3RdXSwgLmRhdGFbW3BjU2Vjb25kXV0sIGxhYmVsID0gc2FtcGxlX2FjY2Vzc2lvbikpICsKICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGRhdGFHRyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHN0dWR5X2FjY2Vzc2lvbiAhPSBpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFRpc3N1ZSAlaW4lIGMoIkNvbmp1bmN0aXZhIiwgIkNvcm5lYSIsICJMZW5zIiwgIlJldGluYSIsIlJQRSIsIlRyYWJlY3VsYXIgTWVzaHdvcmsiKSksIAogICAgICAgICAgICAgICAgICAgICBzaXplPTIsIAogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9LmRhdGFbW3BjRmlyc3RdXSwgeT0gLmRhdGFbW3BjU2Vjb25kXV0pLCBjb2xvciA9ICdncmV5JyApICsKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBhZXMoY29sb3I9U3VzcGljaW91cywgc2hhcGUgPSBTb3VyY2UpKSArCiAgICAgICAgICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKHNpemUgPSAyLjUsIG1heC5vdmVybGFwcyA9IEluZikgKwogICAgICAgICAgeGxhYihwYXN0ZTAocGNGaXJzdCwgIjogIixwZXJjZW50VmFyW3N0cl9leHRyYWN0KHBjRmlyc3QsICdcXGQrJykgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuaW50ZWdlcigpXSwiJSB2YXJpYW5jZSIpKSArCiAgICAgICAgICB5bGFiKHBhc3RlMChwY1NlY29uZCwgIjogIixwZXJjZW50VmFyW3N0cl9leHRyYWN0KHBjU2Vjb25kLCAnXFxkKycpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5pbnRlZ2VyKCldLCIlIHZhcmlhbmNlIikpICsgCiAgICAgICAgICBjb3dwbG90Ojp0aGVtZV9jb3dwbG90KCkgKwogICAgICAgICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDA6MTApICsgZmFjZXRfd3JhcCh+VGlzc3VlLCBuY29sID0gMikKICApCn0KCmBgYAoKCgoKCgo=